package dubbo.server2.impl.controller;

import dubbo.server2.impl.domain.PrintDto;
import org.apache.log4j.Logger;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

@RestController
@RequestMapping("/oom")
public class OOMController {
	private Logger logger = Logger.getLogger(OOMController.class);
	static class OOMObject {
	}
	/**
	 * 堆溢出
	 * VM Args: -Xms40m -Xmx40m -XX:+HeapDumpOnOutOfMemoryError
	 * 描述: -XX:+HeapDumpOnOutOfMemoryError 生成hprof文件，该文件在项目根目录下
	 */
	@RequestMapping("/heap")
	public void heap() {
		List<OOMObject> list = new ArrayList<>();
		while (true) {
			// 疯狂创建对象
			list.add(new OOMObject());
		}
	}
	private int stackLength = 1;
	/**
	 * 栈溢出
	 * VM Args: -Xss200k
	 * 描述: -XX:+HeapDumpOnOutOfMemoryError 命令对栈溢出不会记录，所以没用
	 */
	@RequestMapping("/stack")
	public void stack() {
		while (true) {
			try {
				stack();
			}catch (Exception e){
				System.out.println("stack length:" + stackLength);
				throw e;
			}
		}
	}
	/**
	 * 常量池溢出
	 * VM Args:
	 * jdk6以前：-XX:PermSize=10M -XX:MaxPermSize=10M
	 * jdk7开始：-Xms40m -Xmx40m -XX:-UseGCOverheadLimit -XX:+HeapDumpOnOutOfMemoryError
	 * 描述: -XX:+HeapDumpOnOutOfMemoryError 生成hprof文件，该文件在项目根目录下
	 * ，-XX:-UseGCOverheadLimit是关闭GC占用时间
	 */
	@RequestMapping("/runtimePool")
	public void runtimePool() {
		// 使用list保持常量的引用，避免Full GC回收常量池
		LinkedList<String> list=new LinkedList<>();
		// 疯狂添加常量到list
		int i=1;
		while (true) {
			list.add(String.valueOf(i++).intern());
		}
	}
	/**
	 * 方法区溢出
	 * VM Args:
	 * jdk1.7 方法区位于永久带 -XX:PermSize=40M -XX:MaxPermSize=40M -XX:+HeapDumpOnOutOfMemoryError
	 * jdk1.8 方法区位于元数据带 -XX:MetaspaceSize=40m -XX:MaxMetaspaceSize=40m -XX:+HeapDumpOnOutOfMemoryError
	 * 描述: -XX:+HeapDumpOnOutOfMemoryError 生成hprof文件，该文件在项目根目录下
	 */
	@RequestMapping("/method")
	public void method() {
		int count=0;
		while (true) {
			System.out.println("创建代理类:" + count++);
			Enhancer enhancer = new Enhancer();
			enhancer.setSuperclass(OOMObject.class);
			enhancer.setUseCache(false);
			enhancer.setCallback(new MethodInterceptor() {
				@Override
				public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
					return proxy.invokeSuper(obj, args);
				}
			});
			enhancer.create();
		}
	}
	/**
	 * 本机直接内存溢出，该类执行完ide都崩掉了，小心！！！
	 * VM Args: -Xmx40M -XX:MaxDirectMemorySize=10M
	 */
	@RequestMapping("/direct")
	public void direct() {
		int _1MB = 1024 * 1024;
		Field unsafeField = Unsafe.class.getDeclaredFields()[0];
		unsafeField.setAccessible(true);
		Unsafe unsafe = null;
		try {
			unsafe = (Unsafe) unsafeField.get(null);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		while (true) {
			unsafe.allocateMemory(_1MB);
		}
	}
}
